<?php
declare(strict_types=1);

namespace Service\UserService;

use Service\BaseService;
use Service\Code\Normal;
use App\Model\BbcModel\Member;
use App\Model\BbcModel\ConfigChannel;
use App\Model\BbcModel\AddressSelfdelivery;
use App\Model\BbcModel\MemberInfo;
use App\Model\BbcModel\Area;
use App\Model\BbcModel\Address;
use Service\AuthService\IdCardAuthService;
use Service\AreaService\AreaService;
use Hyperf\DbConnection\Db;

/**
 * TO C/B 收获地址
 * @author hj
 */
class AddressService extends BaseService
{
    /**
     * 收货地址列表
     * @param array $param 包含了系统默认参数
     * @author: hj
     */
    public function addressList(array $param)
    {
        if (!isset($param['mid']) || empty($param['mid']) || (preg_match("/^[1-9]\d*$/", (string)$param['mid']) != 1)) {
            return Normal::returnCode(Normal::FAIL, 'invalid argument mid');
        }
        if (isset($param['page']) && ctype_digit((string)$param['page']) && $param['page'] > 0) {
            $this->page = $param['page'];
        }
        if (isset($param['limit']) && ctype_digit((string)$param['limit']) && $param['limit'] > 0) {
            $this->limit = $param['limit'];
        }
        $fields = ['id', 'true_name', 'idcard', 'mobile', 'province', 'city', 'area', 'address', 'is_default', 'card_front', 'card_back'];
        $model  = Address::where('mid', (int)($param['mid']))->where('df', 0);
        if (isset($param['key_word']) && !empty($param['key_word'])) {
            $keyWord = $param['key_word'];
            $model   = $model->where(function ($query) use ($keyWord) {
                $query->orWhere('true_name', 'like', "%{keyWord}%")->orWhere('address', 'like', "%{keyWord}%");
            });
        }
        $result = $model->select($fields)->orderByRaw("is_default DESC, id DESC")->paginate($this->limit, ['*'], 'page', $this->page);
        if ($result->isEmpty()) {
            return Normal::returnCode(Normal::SUC, '获取成功', ['data' => [], 'count' => 0]);
        }
        $areas        = AreaService::getAreaByCache();
        $show_config  = ConfigChannel::where('code', 'show_config')->where('cid', (int)($param['cid']))->first();
        $show_license = 0;
        $default      = [];
        if (!empty($show_config)) {
            $value        = json_decode($show_config['value'], true);
            $show_license = $value['license'] ?? 0;
        }
        if ($show_license == 1) {
            $default = AddressSelfdelivery::where('cid', (int)($param['cid']))->select(['province', 'city', 'area', 'address',])->first();
            if ($default) {
                $default = $default->toArray();
            }
        }
        $result->each(function ($item, $key) use ($default, $areas) {
            if (!empty($default)) {
                $item->province = $default['province'];
                $item->city     = $default['city'];
                $item->area     = $default['area'];
                $item->address  = $default['address'];
            }
            $item->province = !empty($areas[$item->province]) ? $areas[$item->province] : [];
            $item->city     = !empty($areas[$item->city]) ? $areas[$item->city] : [];
            $item->area     = !empty($areas[$item->area]) ? $areas[$item->area] : [];
            return $item;
        });
        return Normal::returnCode(Normal::SUC, '获取成功', $result->items());
    }

    /**
     * 新增收货地址列表
     * @param array $param 包含了系统默认参数
     * @author: hj
     */
    public function addAddress(array $param)
    {
        $validateRes = self::addArgumentValidate($param);
        if ($validateRes['code'] != Normal::SUC) {
            return Normal::returnCode(Normal::FAIL, $validateRes['msg'] ?? 'invalid argument');
        }
        $param['city'] = !isset($param['city']) || empty($param['city']) ? 0 : $param['city'];
        $param['area'] = !isset($param['area']) || empty($param['area']) ? 0 : $param['area'];
        if (isset($param['idcard']) && !empty($param['idcard'])) {
            $param['idcard'] = strtoupper($param['idcard']);
            $idcardauth      = IdCardAuthService::instance()->checkIdCard(["true_name" => $param['true_name'], "idcard" => $param['idcard'], 'cid' => $param['cid']]);
            if ($idcardauth['code'] != Normal::SUC) {
                return $idcardauth;
            }
        }
        $saveData = [
            'mid'        => $param['mid'],
            'true_name'  => $param['true_name'],
            'idcard'     => $param['idcard'] ?? '',
            'mobile'     => $param['mobile'],
            'province'   => intval($param['province']),
            'city'       => intval($param['city']),
            'area'       => intval($param['area']),
            'address'    => $param['address'],
            'card_front' => $param['card_front'] ?? '',
            'card_back'  => $param['card_back'] ?? '',
            'is_default' => !empty($param['is_default']) ? 1 : 0,
            'cd'         => time(),
        ];
        Db::beginTransaction();
        try {
            $model    = Address::make($saveData);
            $modelRes = $model->save();
            if (!$modelRes) {
                throw new \RuntimeException("新增失败");
            }
            //若新增的地址为默认地址
            if ($saveData['is_default'] == 1) {
                Address::where('mid', (int)($param['mid']))->where('id', '<>', $model->id)->where('is_default', 1)->update(['is_default' => 0, 'md' => time()]);
            }
            Db::commit();
        } catch (\Throwable $th) {
            Db::rollBack();
            return Normal::returnCode(Normal::FAIL, '新增失败' . $th->getMessage());
        }
        return Normal::returnCode(Normal::SUC, '新增成功', ['id' => $model->id]);
    }

    /**
     * 编辑收货地址列表
     * @param array $param 包含了系统默认参数
     * @author: hj
     */
    public function editAddress(array $param)
    {
        if (!isset($param['id']) || empty($param['id']) || (preg_match("/^[1-9]\d*$/", (string)$param['id']) != 1)) {
            return Normal::returnCode(Normal::FAIL, 'invalid argument id');
        }
        $validateRes = self::addArgumentValidate($param);
        if ($validateRes['code'] != Normal::SUC) {
            return Normal::returnCode(Normal::FAIL, $validateRes['msg'] ?? 'invalid argument');
        }
        $address = Address::where('id', (int)($param['id']))->where('mid', (int)($param['mid']))->where('df', 0)->first();
        if (empty($address)) {
            return Normal::returnCode(Normal::FAIL, '地址信息不存在');
        }
        if (isset($param['idcard']) && !empty($param['idcard'])) {
            $param['idcard'] = strtoupper($param['idcard']);
            $idcardauth      = IdCardAuthService::instance()->checkIdCard(["true_name" => $param['true_name'], "idcard" => $param['idcard'], 'cid' => $param['cid']]);
            if ($idcardauth['code'] != Normal::SUC) {
                return $idcardauth;
            }
        }

        Db::beginTransaction();
        try {
            $address->mid        = $param['mid'];
            $address->true_name  = $param['true_name'];
            $address->idcard     = $param['idcard'] ?? '';
            $address->mobile     = $param['mobile'];
            $address->province   = intval($param['province']);
            $address->city       = intval($param['city']);
            $address->area       = intval($param['area']);
            $address->address    = $param['address'];
            $address->card_front = $param['card_front'] ?? '';
            $address->card_back  = $param['card_back'] ?? '';
            $address->is_default = !empty($param['is_default']) ? 1 : 0;
            $address->md         = time();
            $saveRes             = $address->save();
            if (!$saveRes) {
                throw new \RuntimeException("修改失败");
            }
            //若新增的地址为默认地址
            if ($address->is_default == 1) {
                Address::where('mid', (int)($param['mid']))->where('id', '<>', $address->id)->where('is_default', 1)->update(['is_default' => 0, 'md' => time()]);
            }
            Db::commit();
        } catch (\Throwable $th) {
            Db::rollBack();
            return Normal::returnCode(Normal::FAIL, '修改失败' . $th->getMessage());
        }
        $info = self::addressInfo(['id' => $param['id'], 'mid' => $param['mid'], 'cid' => $param['cid']]);
        return Normal::returnCode(Normal::SUC, '修改成功', $info['data']);
    }

    /**
     * 删除收货地址
     * @param array $param 包含了系统默认参数
     * @author: hj
     */
    public function delAddress(array $param)
    {
        if (!isset($param['mid']) || empty($param['mid']) || (preg_match("/^[1-9]\d*$/", (string)$param['mid']) != 1)) {
            return Normal::returnCode(Normal::FAIL, 'invalid argument mid');
        }
        if (!isset($param['id']) || empty($param['id'])) {
            return Normal::returnCode(Normal::FAIL, 'invalid argument id');
        }
        $address = Address::where('id', (int)($param['id']))->where('mid', (int)($param['mid']))->where('df', 0)->first();
        if (!$address) {
            return Normal::returnCode(Normal::FAIL, '地址信息不存在');
        }
        $address->df = 1;
        $address->md = time();
        $result      = $address->save();
        if (!$result) {
            return Normal::returnCode(Normal::FAIL, '删除失败');
        }
        return Normal::returnCode(Normal::SUC, '删除成功');
    }

    /**
     * 传入地址信息自动识别，并返回最高匹配结果
     * 如果地址新增，则需要删除缓存文件重新缓存
     * @param array $param 包含了系统默认参数
     * @author: hj
     */
    public function getAddressResult(array $param)
    {
        if (!isset($param['address']) || empty($param['address'])) {
            return Normal::returnCode(Normal::FAIL, 'invalid argument address');
        }
        $address = $param['address'];
        $search  = ['收货地址', '地址', '收货人', '收件人', '收货', '邮编', '电话', '身份证号码', '身份证号', '身份证', '；', '：', ':', ';', ',', '.', '。', '，'];
        $replace = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''];
        $address = str_replace($search, $replace, $address);
        $result  = self::getAddressArrar($address);
        if (isset($result['code']) && $result['code'] == Normal::FAIL) {
            $result['level'] = 0;
        }
        // 如果结果不理想，再模糊去匹配
        if ($result['level'] != 3) {
            $result_sub = self::addressVague($address);
            if (isset($result_sub['code']) && $result_sub['code'] == Normal::FAIL) {
                return $result_sub;
            }
            // 只有全匹配对才替换，否则不做任何改变
            if ($result_sub['level'] == 3) {
                $result = $result_sub;
            }
        }
        $result['mobile'] = '';
        $result['name']   = '';
        // 联系方式-优先匹配电话
        if (preg_match('/1\d{10}/', $address, $mobiles)) {
            $result['mobile'] = $mobiles[0];
        }
        $left = mb_stripos($address, '1');
        if ($left === false) {
            return Normal::returnCode(Normal::FAIL, '手机号未找到');
        }
        $result['name'] = mb_substr($address, 0, $left, 'utf-8');
        // 去掉详细里面的姓名和电话
        $result['info'] = str_replace($result['mobile'], '', $result['info']);
        $result['info'] = str_replace($result['name'], '', $result['info']);
        if (isset($result['name_num'])) {
            unset($result['name_num']);
        }
        unset($result['level']);
        $data = self::getCityLevelList($result);
        return Normal::returnCode(Normal::SUC, '识别成功', $data);
    }

    /**
     * 默认收货地址
     * @param array $param 包含了系统默认参数
     * @author: hj
     */
    public function getDefaultAddress(array $param)
    {
        if (!isset($param['cid']) || empty($param['cid'])) {
            return Normal::returnCode(Normal::FAIL, 'invalid argument cid');
        }
        $show_config  = ConfigChannel::where('code', 'show_config')->where('cid', (int)($param['cid']))->first();
        $show_license = 0;
        if (!empty($show_config)) {
            $value        = json_decode($show_config['value'], true);
            $show_license = $value['license'] ?? 0;
        }
        if ($show_license == 1) {
            $default = AddressSelfdelivery::where('cid', (int)($param['cid']))->select(['province', 'city', 'area', 'address',])->first();
            if (!empty($default)) {
                $default             = $default->toArray();
                $areas               = AreaService::getAreaByCache();
                $default['province'] = $areas[$default['province']];
                $default['city']     = $areas[$default['city']];
                $default['area']     = $areas[$default['area']];
                return Normal::returnCode(Normal::SUC, '获取成功', $default);
            }
        }
        return Normal::returnCode(Normal::SUC, '获取成功', []);
    }

    /**
     * 第一种方法
     * 根据地址列表递归查找准确地址
     * @param $address
     */
    protected static function getAddressArrar($address)
    {
        // 获取所有地址递归列表
        $regions = AreaService::getRegionTreeList();
        // 初始化数据
        $province = $city = $district = [];
        // 先查找省份-第一级地区
        $province = self::checkAddress($address, $regions);
        if ($province) {
            // 查找城市-第二级地区
            $city = self::checkAddress($address, $province['list']);
            if ($city) {
                // 查找地区-第三级地区
                // 西藏自治区 那曲市 色尼区辽宁南路西藏公路 第三个参数因为这个地址冲突取消强制
                $district = self::checkAddress($address, $city['list']);
            }
        }
        return self::getAddressInfo($address, $province, $city, $district);
    }

    /**
     * 第二种方法
     * 地址模糊查找
     */
    protected static function addressVague($address)
    {
        $res = preg_match_all('/\S{2}[自市区镇县乡岛州]/iu', $address, $arr);
        if (!$res) return false;
        $where = '';
        foreach ($arr[0] as $value) {
            if (strpos($value, '小区') === false && strpos($value, '开发区') === false) {
                $where .= " name like '%{$value}' or ";
            }
        }
        $where = substr($where, 0, -3);
        $citys = Area::select(['id', 'name', 'pid', 'deep'])->whereRaw($where)->get()->toArray();
        // 匹配所有地址
        $result = [];
        foreach ($citys as &$city) {
            // 所有相关联的地区id
            $city_ids = [];
            if ($city['deep'] == 2) {
                $city_ids = array($city['pid'], $city['id']);
                // 尝试能不能匹配第三级
                $areas = Area::selectRaw("id,name,pid,deep,left(name,2) as ab_name")->whereRaw("pid='{$city['id']}'")->get()->toArray();
                foreach ($areas as $row) {
                    if (mb_strpos($address, $row['ab_name'])) {
                        $city_ids[] = $row['id'];
                    }
                }
            } else if ($city['deep'] == 3) {
                $father              = Area::selectRaw("pid")->whereRaw("id='{$city['pid']}'")->get()->toArray();
                $city['province_id'] = $father[0]['pid'] ?? 0;
                $city_ids            = array($city['pid'], $city['id'], $city['province_id']);
            }
            // 查找该单词所有相关的地区记录
            $city_list = Area::selectRaw("id,name,pid,deep,left(name,2) as ab_name")->whereRaw("id in(" . join(',', $city_ids) . ")")->orderBy('id', 'asc')->get()->toArray();
            sort($city_ids);
            $key          = array_pop($city_ids);
            $result[$key] = $city_list;
            sort($result);
        }
        if ($result) {
            unset($city);
            list($province, $city, $area) = $result[0];
            return self::getAddressInfo($address, $province, $city, $area);
        }
        return Normal::returnCode(Normal::FAIL, '识别失败');
    }

    /**
     * 匹配正确的城市地址
     */
    protected static function checkAddress($address, $city_list, $force = false, $str_len = 2)
    {
        $num    = 0;
        $list   = [];
        $result = [];
        // 遍历所有可能存在的城市
        foreach ($city_list as $city_key => $city) {
            $city_name = mb_substr($city['name'], 0, $str_len, 'utf-8');
            // 判断是否存包含当前地址字符
            $city_arr = explode($city_name, $address);
            // 如果存在相关字眼，保存该地址的所有子地址
            if (count($city_arr) >= 2) {
                // 必须名称长度同时达到当前比对长度
                if (strlen($city['name']) < $str_len) {
                    continue;
                }
                $num++;
                $list     = $list + $city['childs'];
                $result[] = array(
                    'id'   => $city['id'],
                    'name' => $city['name'],
                    'list' => $list,
                );
            }
        }
        // 如果有多个存在，则加大字符匹配长度
        if ($num > 1 || $force) {
            $region_name1 = $result[0]['name'];
            $region_name2 = $result[1]['name'];
            if (strlen($region_name1) == strlen($region_name2) && strlen($region_name1) == $str_len) {
                $id1   = $result[0]['id'];
                $id2   = $result[1]['id'];
                $index = $id1 > $id2 ? 1 : 0;
                return $result[$index];
            }
            return self::checkAddress($address, $city_list, $force, $str_len + 1);
        } else {
            $result[0]['list'] = $list;
            return $result[0];
        }
    }

    /**
     * 根据原地址返回详细信息
     */
    protected static function getAddressInfo($address, $province, $city, $district)
    {
        // 查找最后出现的地址 - 截取详细信息
        $find_str = '';
        if (empty($province['name'])) {
            return Normal::returnCode(Normal::FAIL, '识别失败');
        }
        if ($province['name']) {
            $find_str = $province['name'];
            if ($city['name']) {
                $find_str = $city['name'];
                if ($district['name']) {
                    $find_str = $district['name'];
                }
            }
        }
        // 截取详细的信息
        $find_str_len = mb_strlen($find_str, 'utf-8');
        for ($i = 0; $i < $find_str_len - 1; $i++) {
            $substr    = mb_substr($find_str, 0, $find_str_len - $i, 'utf-8');
            $end_index = mb_strpos($address, $substr);
            if ($end_index) {
                $address = mb_substr($address, $end_index + mb_strlen($substr), mb_strlen($address) - $end_index);
            }
        }
        !empty($find_str) && $find_str = '|\S*' . $find_str;
        $area['info'] = preg_replace("/\s*|,|，|:|：{$find_str}/i", '', $address);
        $level        = 0;
        if ($district['name']) {
            $level = 3;
        } else if ($city['name']) {
            $level = 2;
        } else if ($province['name']) {
            $level = 1;
        }
        return [
            'province' => array('id' => $province['id'], 'name' => $province['name']),
            'city'     => array('id' => $city['id'], 'name' => $city['name']),
            'district' => array('id' => $district['id'], 'name' => $district['name']),
            'info'     => $area['info'],
            'level'    => $level,
        ];
    }

    /**
     * 获取对应城市等级列表
     **/
    protected static function getCityLevelList($result)
    {
        // 获取所有地址递归列表
        $regions = AreaService::getRegionTreeList();
        // 获取省份列表- 只有存在值才返回对应列表
        $province_id = $result['province']['id'];
        if ($province_id) {
            foreach ($regions as $region) {
                unset($region['childs']);
                $result['province_list'][] = $region;
            }
        }
        // 获取城市列表- 只有存在值才返回对应列表
        $city_id = $result['city']['id'];
        if ($city_id) {
            foreach ($regions[$province_id]['childs'] as $region) {
                unset($region['childs']);
                $result['city_list'][] = $region;
            }
        }
        // 获取地区列表- 只有存在值才返回对应列表
        $district_id = $result['district']['id'];
        if ($district_id) {
            foreach ($regions[$province_id]['childs'][$city_id]['childs'] as $region) {
                unset($region['childs']);
                $result['district_list'][] = $region;
            }
        }
        return $result;
    }

    /**
     * 个人地址信息详情
     */
    protected static function addressInfo($param)
    {
        if (!isset($param['mid']) || empty($param['mid']) || (preg_match("/^[1-9]\d*$/", (string)$param['mid']) != 1)) {
            return Normal::returnCode(Normal::FAIL, 'invalid argument mid');
        }
        if (!isset($param['cid']) || empty($param['cid'])) {
            return Normal::returnCode(Normal::FAIL, 'invalid argument cid');
        }
        $model = Address::where('mid', (int)($param['mid']))->where('df', 0);
        if (isset($param['id']) && !empty($param['id'])) {
            $model = $model->where('id', (int)($param['id']));
        }
        if (isset($param['is_default']) && !empty($param['is_default'])) {
            $model = $model->where('is_default', 1);
        }
        $fields  = ['id', 'true_name', 'idcard', 'mobile', 'province', 'city', 'area', 'address', 'is_default', 'md', 'card_front', 'card_back'];
        $address = $model->select($fields)->orderByRaw("is_default DESC, id DESC")->first();
        if (empty($address)) {
            return Normal::returnCode(Normal::FAIL, '地址信息不存在');
        }
        $address      = $address->toArray();
        $show_config  = ConfigChannel::where('code', 'show_config')->where('cid', (int)($param['cid']))->first();
        $show_license = 0;
        if (!empty($show_config)) {
            $value        = json_decode($show_config['value'], true);
            $show_license = $value['license'] ?? 0;
        }
        if ($show_license == 1) {
            $default = AddressSelfdelivery::where('cid', (int)($param['cid']))->select(['province', 'city', 'area', 'address',])->first();
            if ($default) {
                $default             = $default->toArray();
                $address['province'] = $default['province'];
                $address['city']     = $default['city'];
                $address['area']     = $default['area'];
                $address['address']  = $default['address'];
            }
        }
        $areas               = AreaService::getAreaByCache();
        $address['province'] = !empty($areas[$address['province']]) ? $areas[$address['province']] : [];
        $address['city']     = !empty($areas[$address['city']]) ? $areas[$address['city']] : [];
        $address['area']     = !empty($areas[$address['area']]) ? $areas[$address['area']] : [];
        $memberInfo          = MemberInfo::where('mid', (int)($param['mid']))->select(['truename', 'mobile', 'idcard', 'card_front', 'card_back'])->first();
        $address['buyer']    = $memberInfo ? $memberInfo->toArray() : [];
        return Normal::returnCode(Normal::SUC, '获取成功', $address);
    }

    /**
     * 添加参数验证
     * @author: hj
     */
    private static function addArgumentValidate($param)
    {
        if (!isset($param['mid']) || empty($param['mid']) || (preg_match("/^[1-9]\d*$/", (string)$param['mid']) != 1)) {
            return Normal::returnCode(Normal::FAIL, 'invalid argument mid');
        }
        $member = Member::where('mid', (int)($param['mid']))->exists();
        if (empty($member)) {
            return Normal::returnCode(Normal::FAIL, '用户不存在');
        }
        if (!isset($param['true_name']) || empty($param['true_name'])) {
            return Normal::returnCode(Normal::FAIL, '请输入收货人');
        }
        if (!isset($param['cid']) || empty($param['cid'])) {
            return Normal::returnCode(Normal::FAIL, 'invalid argument cid');
        }
        if (!isset($param['mobile']) || empty($param['mobile'])) {
            return Normal::returnCode(Normal::FAIL, '请输入收货人手机');
        }
        if (!isset($param['province']) || empty($param['province'])) {
            return Normal::returnCode(Normal::FAIL, '请选择省');
        }
        if (!isset($param['address']) || empty($param['address'])) {
            return Normal::returnCode(Normal::FAIL, '请输入详细地址');
        }
        return Normal::returnCode(Normal::SUC, '验证通过');
    }
}